package com.popreal.shop.helper;

import java.net.InetAddress;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisException;

public class RedisHelper {

    private JedisPool redisPool;

    private int expireSeconds = 1800;//30分钟后删除

    private final static String SERVER_NAME;

    static {
        StringBuffer sb = new StringBuffer();
        try {
            InetAddress address = InetAddress.getLocalHost();
            sb.append(address.getHostName()).append("_");
            sb.append(address.getHostAddress());
        } catch (Exception e) {
        }
        if(sb.length() == 0) {
            sb.append("Unknow host");
        }
        SERVER_NAME = sb.toString();
    }

    public static abstract class RedisCallback<T>{
        public abstract T execute(Jedis redis);
        public void error(JedisException e){
        }
    }

    public <T> T use(RedisCallback<T> redisCallback){
        Jedis redis = null;
        try {
            redis = redisPool.getResource();
            return redisCallback.execute(redis);
        } finally {
            if (null != redis) {
            	redis.close();
            }
        }
    }

    /**
     * 同步，
     * @param o 锁的Key
     * @param blockTime 阻塞时间内偿试获得锁,单位毫秒
     * @param callBack 回调
     */
    public void syn(Object o, final long blockTime, final CallBack callBack){
        final String lock = o.toString();
        this.use(new RedisHelper.RedisCallback<Object>() {
            @Override
            public Object execute(Jedis redis) {
                long count = 0, allTime = 0;
                //偿试获得锁
                do{
                    count = redis.setnx(lock, SERVER_NAME);
                    if(count == 0) {
                        try {
                            Thread.sleep(200);
                        } catch (Exception e) {
                        }
                        allTime += 200;
                    }else {
                        break ;
                    }
                }while (allTime <= blockTime);

                try {
                    if(count == 0) {
                        //某台机器在处理了
                        callBack.fail();
                    }else {
                        redis.expire(lock, expireSeconds);
                        callBack.key = lock;
                        callBack.redis = redis;
                        callBack.success();
                    }
                }finally {
                	if(count != 0) {
                        redis.del(lock);
                	}
                }
                return null;
            }
        });
    }

    public static abstract class CallBack {
        String key;
        Jedis redis;

        /**
         * 删除锁，主要用于优先级较低的锁
         */
        public void clearLock(){
            redis.del(key);
        }

        public abstract void success();

        public abstract void fail();
    }

    public void setRedisPool(JedisPool redisPool) {
        this.redisPool = redisPool;
    }

	public JedisPool getRedisPool() {
		return redisPool;
	}
    
}
